package cn.stylefeng.guns.sys.modular.system.db2.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.stylefeng.guns.base.pojo.page.LayuiPageFactory;
import cn.stylefeng.guns.base.pojo.page.LayuiPageInfo;
import cn.stylefeng.guns.sys.core.util.DateUtil;
import cn.stylefeng.guns.sys.modular.system.db2.mapper.BusinessMapper;
import cn.stylefeng.guns.sys.modular.system.db2.model.params.BusinessParam;
import cn.stylefeng.guns.sys.modular.system.db2.service.BusinessService;
import cn.stylefeng.guns.sys.modular.system.model.params.ProDataViewParam;
import cn.stylefeng.guns.sys.modular.system.model.result.ShopDataResult;
import cn.stylefeng.roses.core.reqres.response.ResponseData;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.text.NumberFormat;
import java.text.ParseException;
import java.util.*;

/**
 * <p>
 * 服务实现类
 * </p>
 *
 * @author jiangge
 * @since 2020-10-27
 */
@Service
public class BusinessServiceImpl implements BusinessService {

    @Resource
    private BusinessMapper businessMapper;

    @Override
    public LayuiPageInfo findPageBySpec(BusinessParam param) {
        Page pageContext = getPageContext();
        IPage page = businessMapper.customPageList(pageContext, param);
        return LayuiPageFactory.createPageInfo(page);
    }

    @Override
    public ResponseData findBusinessData(ProDataViewParam param) throws ParseException {

        Map<String, Object> businessData = findBusinessDataByParam(param);

        if (businessData != null) {

            //昨日
            String startTime2 = DateUtil.getYearstoday(param.getDate().trim()) + " 04:00:00";
            String endTime2 = DateUtil.get4OclockByDay(DateUtil.getYearstoday(param.getDate().trim()));
            param.setStartTime(startTime2);
            param.setEndTime(endTime2);
            Map<String, Object> yesBusinessData = findBusinessDataByParam(param);
            if (yesBusinessData != null && yesBusinessData.get("income") != null) {
                businessData.put("yesIncome", yesBusinessData.get("income"));
            }

            //环比昨日
            BigDecimal thanYesNum = calculateTheDiff(businessData == null ? BigDecimal.ZERO : businessData.get("income"), yesBusinessData == null ? BigDecimal.ZERO : yesBusinessData.get("income"));
            businessData.put("thanYesNum", thanYesNum);
            String thanYesRatio = calculateTheRatio(businessData.get("income"), yesBusinessData == null ? BigDecimal.ZERO : yesBusinessData.get("income"));
            businessData.put("thanYesRatio", thanYesRatio);

            //上周本日
            String startTime3 = DateUtil.getToDayLastWeek(param.getDate().trim()) + " 04:00:00";
            String endTime3 = DateUtil.get4OclockByDay(DateUtil.getToDayLastWeek(param.getDate().trim()));
            param.setStartTime(startTime3);
            param.setEndTime(endTime3);
            Map<String, Object> lastWeekThisDayBusinessData = findBusinessDataByParam(param);
            if (lastWeekThisDayBusinessData != null && lastWeekThisDayBusinessData.get("income") != null) {
                businessData.put("lastWeekThisDayIncome", lastWeekThisDayBusinessData.get("income"));
            }

            //同比上周本日
            BigDecimal thanWeekNum = calculateTheDiff(businessData == null ? BigDecimal.ZERO : businessData.get("income"), lastWeekThisDayBusinessData == null ? BigDecimal.ZERO : lastWeekThisDayBusinessData.get("income"));
            businessData.put("thanWeekNum", thanWeekNum);
            String thanWeekRatio = calculateTheRatio(businessData.get("income"), lastWeekThisDayBusinessData == null ? BigDecimal.ZERO : lastWeekThisDayBusinessData.get("income"));
            businessData.put("thanWeekRatio", thanWeekRatio);
            //本周累计
            List<String> thisWeek = DateUtil.getThisWeekIntervalToThisDay(param.getDate().trim());
            String startTime4 = thisWeek.get(0) + " 04:00:00";
            String endTime4 = DateUtil.get4OclockByDay(thisWeek.get(thisWeek.size() - 1));
            param.setStartTime(startTime4);
            param.setEndTime(endTime4);
            Map<String, Object> thisWeekBusinessData = findBusinessDataByParam(param);
            if (thisWeekBusinessData != null && thisWeekBusinessData.get("income") != null) {
                businessData.put("thisWeekIncome", thisWeekBusinessData.get("income"));
            }
            //上周累计
            List<String> lastWeek = DateUtil.getLastWeekInterval(param.getDate().trim());
            String startTime5 = lastWeek.get(0) + " 04:00:00";
            String endTime5 = DateUtil.get4OclockByDay(lastWeek.get(lastWeek.size() - 1));
            param.setStartTime(startTime5);
            param.setEndTime(endTime5);
            Map<String, Object> lastWeekBusinessData = findBusinessDataByParam(param);
            if (lastWeekBusinessData != null && lastWeekBusinessData.get("income") != null) {
                businessData.put("lastWeekIncome", lastWeekBusinessData.get("income"));
            }
            //本月累计
            List<String> thisMonth = DateUtil.getBetweenDate(DateUtil.getMonthFirstDayByDay(param.getDate().trim()), param.getDate().trim());
            String startTime6 = thisMonth.get(0) + " 04:00:00";
            String endTime6 = DateUtil.get4OclockByDay(thisMonth.get(thisMonth.size() - 1));
            param.setStartTime(startTime6);
            param.setEndTime(endTime6);
            Map<String, Object> thisMonthBusinessData = findBusinessDataByParam(param);
            if (thisMonthBusinessData != null && thisMonthBusinessData.get("income") != null) {
                businessData.put("thisMonthIncome", thisMonthBusinessData.get("income"));
            }

            //上月累计
            List<String> lastMonth = DateUtil.getMonthFullDay(DateUtil.lastMonthByDate(param.getDate().trim()));
            String startTime7 = lastMonth.get(0) + " 04:00:00";
            String endTime7 = DateUtil.get4OclockByDay(lastMonth.get(lastMonth.size() - 1));
            param.setStartTime(startTime7);
            param.setEndTime(endTime7);
            Map<String, Object> lastMonthBusinessData = findBusinessDataByParam(param);
            if (lastMonthBusinessData != null && lastMonthBusinessData.get("income") != null) {
                businessData.put("lastMonthIncome", lastMonthBusinessData.get("income"));
            }
            return ResponseData.success(200, ResponseData.DEFAULT_SUCCESS_MESSAGE, businessData);
        }

        return ResponseData.success(200, ResponseData.DEFAULT_SUCCESS_MESSAGE, null);
    }


    @Override
    public ResponseData findBusinessDataOfDineIn(ProDataViewParam param) throws ParseException {

        Map<String, Object> businessData = findBusinessDataByParam(param);

        if (businessData != null) {
            //优惠占比
            String discountRatio = calculateRatio(businessData == null ? BigDecimal.ZERO : businessData.get("disctotal"), businessData == null ? BigDecimal.ZERO : businessData.get("income"));
            businessData.put("discountRatio", discountRatio);

            //上周本日
            String startTime3 = DateUtil.getToDayLastWeek(param.getDate().trim()) + " 04:00:00";
            String endTime3 = DateUtil.get4OclockByDay(DateUtil.getToDayLastWeek(param.getDate().trim()));
            param.setStartTime(startTime3);
            param.setEndTime(endTime3);
            Map<String, Object> lastWeekThisDayBusinessData = findBusinessDataByParam(param);
            if (lastWeekThisDayBusinessData != null && lastWeekThisDayBusinessData.get("count") != null) {
                businessData.put("lastWeekThisDayCount", lastWeekThisDayBusinessData.get("count"));
            }

            //同比上周本日
            BigDecimal thanWeekNum = calculateTheDiff(businessData == null ? BigDecimal.ZERO : businessData.get("count"), lastWeekThisDayBusinessData == null ? BigDecimal.ZERO : lastWeekThisDayBusinessData.get("count"));
            businessData.put("thanWeekNum", thanWeekNum);
            String thanWeekRatio = calculateTheRatio(businessData.get("count"), lastWeekThisDayBusinessData == null ? BigDecimal.ZERO : lastWeekThisDayBusinessData.get("count"));
            businessData.put("thanWeekRatio", thanWeekRatio);

            //单均
            BigDecimal avgIncome = calculateAvgIncome(businessData == null ? BigDecimal.ZERO : businessData.get("income"), businessData == null ? BigDecimal.ZERO : businessData.get("count"));
            businessData.put("avgIncome", avgIncome);

            return ResponseData.success(200, ResponseData.DEFAULT_SUCCESS_MESSAGE, businessData);
        }

        return ResponseData.success(200, ResponseData.DEFAULT_SUCCESS_MESSAGE, null);
    }

    @Override
    public ResponseData findBusinessDataOfTakeAway(ProDataViewParam param) throws ParseException {
        Map<String, Object> businessData = businessMapper.findBusinessDataOfTakeAway(param);
        if (businessData != null) {
            //实际收入
            BigDecimal incometotal = businessData.get("incometotal") == null ? BigDecimal.ZERO : (BigDecimal) businessData.get("incometotal");
            businessData.put("incometotal", incometotal.setScale(2, BigDecimal.ROUND_HALF_UP));

            //优惠占比
            String discountRatio = calculateRatio(businessData == null ? BigDecimal.ZERO : businessData.get("disctotal"), businessData == null ? BigDecimal.ZERO : businessData.get("income"));
            businessData.put("discountRatio", discountRatio);

            //上周本日
            String startTime3 = DateUtil.getToDayLastWeek(param.getDate().trim()) + " 04:00:00";
            String endTime3 = DateUtil.get4OclockByDay(DateUtil.getToDayLastWeek(param.getDate().trim()));
            param.setStartTime(startTime3);
            param.setEndTime(endTime3);
            Map<String, Object> lastWeekThisDayBusinessData = businessMapper.findBusinessDataOfTakeAway(param);
            if (lastWeekThisDayBusinessData != null && lastWeekThisDayBusinessData.get("count") != null) {
                businessData.put("lastWeekThisDayCount", lastWeekThisDayBusinessData.get("count"));
                //同比上周商家优惠-数目
                BigDecimal lastWeekShopPart = lastWeekThisDayBusinessData.get("shoppart") == null ? BigDecimal.ZERO : (BigDecimal) lastWeekThisDayBusinessData.get("shoppart");
                businessData.put("lastWeekShopPart", lastWeekShopPart);
            }

            //同比上周本日-单数
            BigDecimal thanWeekNum = calculateTheDiff(businessData == null ? BigDecimal.ZERO : businessData.get("count"), lastWeekThisDayBusinessData == null ? BigDecimal.ZERO : lastWeekThisDayBusinessData.get("count"));
            businessData.put("thanWeekNum", thanWeekNum);
            String thanWeekRatio = calculateTheRatio(businessData == null ? BigDecimal.ZERO : businessData.get("count"), lastWeekThisDayBusinessData == null ? BigDecimal.ZERO : lastWeekThisDayBusinessData.get("count"));
            businessData.put("thanWeekRatio", thanWeekRatio);

            //商家优惠
            BigDecimal shoppart = businessData.get("shoppart") == null ? BigDecimal.ZERO : (BigDecimal) businessData.get("shoppart");
            businessData.put("shoppart", shoppart.setScale(2, BigDecimal.ROUND_HALF_UP));

            //同比上周商家的优惠
            BigDecimal thanWeekShopPartNum = calculateTheDiff(shoppart, lastWeekThisDayBusinessData == null ? BigDecimal.ZERO : businessData.get("lastWeekShopPart"));
            businessData.put("thanWeekShopPartNum", thanWeekShopPartNum);

            String thanWeekShopPartRatio = calculateTheRatio(shoppart, businessData.get("lastWeekShopPart"));
            businessData.put("thanWeekShopPartRatio", thanWeekShopPartRatio);


            //单均
            BigDecimal avgIncome = calculateAvgIncome(businessData == null ? BigDecimal.ZERO : businessData.get("incometotal"), businessData == null ? BigDecimal.ZERO : businessData.get("count"));
            businessData.put("avgIncome", avgIncome);

            //平台服务费
            BigDecimal servicefee = businessData.get("servicefee") == null ? BigDecimal.ZERO : (BigDecimal) businessData.get("servicefee");

            businessData.put("servicefee", servicefee.setScale(2, BigDecimal.ROUND_HALF_UP));

            return ResponseData.success(200, ResponseData.DEFAULT_SUCCESS_MESSAGE, businessData);
        }

        return ResponseData.success(200, ResponseData.DEFAULT_SUCCESS_MESSAGE, null);
    }

    @Override
    public LinkedHashMap<String, Object> findRecentDaysBusinessData(ProDataViewParam param) throws ParseException {

        LinkedHashMap<String, Object> map = new LinkedHashMap<>();

        //几天前日期
        String day = DateUtil.getDay(param.getDate().trim(), -1 - param.getParam());
        param.setDate(day);

        for (int i = 0; i < param.getParam(); i++) {

            String startTime2 = DateUtil.getDay(param.getDate().trim(), 1) + " 04:00:00";

            String endTime2 = DateUtil.get4OclockByDay(DateUtil.getDay(param.getDate().trim(), 1));
            param.setStartTime(startTime2);
            param.setEndTime(endTime2);
            Map<String, Object> yesBusinessData = findBusinessDataByParam(param);
            param.setDate(DateUtil.getDay(param.getDate().trim(), 1));
            if (yesBusinessData != null && yesBusinessData.get("income") != null) {
                map.put(param.getDate().trim(), yesBusinessData.get("income"));
            }else {
                map.put(param.getDate().trim(), BigDecimal.ZERO);
            }

        }
        return map;
    }

    /**
     * (income-income1)/income
     *
     * @param income
     * @param income1
     * @return
     */
    private String calculateTheRatio(Object income, Object income1) {
        BigDecimal bigDecimal = calculateTheDiff(income, income1);
        if (income1 == null || ((BigDecimal) income1).compareTo(BigDecimal.ZERO) == 0) {
            return "100.00%";
        }

        if (income == null || ((BigDecimal) income).compareTo(BigDecimal.ZERO) == 0) {
            return "0.00%";
        }

        BigDecimal bigDecimal1 = bigDecimal.divide((BigDecimal) income1, 6, BigDecimal.ROUND_UP);
        //下面将结果转化成百分比
        NumberFormat percent = NumberFormat.getPercentInstance();
        percent.setMaximumFractionDigits(2);
        return percent.format(bigDecimal1.doubleValue());
    }

    private BigDecimal calculateTheDiff(Object income, Object income1) {
        if (income == null || ((BigDecimal) income).compareTo(BigDecimal.ZERO) == 0) {
            return income1 == null ? BigDecimal.ZERO : BigDecimal.ZERO.subtract((BigDecimal) income1);
        }
        if (income1 == null || ((BigDecimal) income1).compareTo(BigDecimal.ZERO) == 0) {
            return income == null ? BigDecimal.ZERO : (BigDecimal) income;
        }
        BigDecimal num1 = (BigDecimal) income;
        BigDecimal num2 = (BigDecimal) income1;
        BigDecimal subtract = num1.subtract(num2).setScale(2,BigDecimal.ROUND_HALF_UP);
        return subtract;
    }

    private String calculateRatio(Object income, Object income1) {
        BigDecimal bigDecimal = (BigDecimal) income;
        if (income1 == null || ((BigDecimal) income1).compareTo(BigDecimal.ZERO) == 0) {
            return "100.00%";
        }

        if (income == null || ((BigDecimal) income).compareTo(BigDecimal.ZERO) == 0) {
            return "0.00%";
        }

        BigDecimal bigDecimal1 = bigDecimal.divide((BigDecimal) income1, 6, BigDecimal.ROUND_UP);
        //下面将结果转化成百分比
        NumberFormat percent = NumberFormat.getPercentInstance();
        percent.setMaximumFractionDigits(2);
        return percent.format(bigDecimal1.doubleValue());
    }

    /**
     * income/income1
     *
     * @param income
     * @param income1
     * @return
     */
    private BigDecimal calculateAvgIncome(Object income, Object income1) {
        BigDecimal bigDecimal = (BigDecimal) income;
        if (income1 == null || ((BigDecimal) income1).compareTo(BigDecimal.ZERO) == 0) {
            return bigDecimal;
        }

        if (income == null || ((BigDecimal) income).compareTo(BigDecimal.ZERO) == 0) {
            return BigDecimal.ZERO;
        }

        BigDecimal bigDecimal1 = bigDecimal.divide((BigDecimal) income1, 2, BigDecimal.ROUND_HALF_UP);
        return bigDecimal1;
    }

    private Map<String, Object> findBusinessDataByParam(ProDataViewParam param) {
        Map<String, Object> businessData = businessMapper.findBusinessData(param);
        return businessData;
    }

    @Override
    public List<Map<String, Object>> findBusinessDataOrderByIncome(ProDataViewParam param) {
        List<Map<String, Object>> businessData = businessMapper.findBusinessDataOrderByIncome(param);
        return businessData;
    }

    @Override
    public ShopDataResult findBusinessDataWithIncomeTotalOrderByIncome(ProDataViewParam param) {
        List<Map<String, Object>> businessData = businessMapper.findBusinessDataOrderByIncome(param);

        BigDecimal incomeTotal=BigDecimal.ZERO;
        if(CollectionUtil.isNotEmpty(businessData)){
            for(Map<String, Object> data:businessData){
                incomeTotal=incomeTotal.add(data.get("income") == null ? BigDecimal.ZERO : (BigDecimal) data.get("income"));
            }
        }

        ShopDataResult dataInfoResult=new ShopDataResult();
        dataInfoResult.setList(businessData);
        dataInfoResult.setIncomeTotal(incomeTotal);
        return dataInfoResult;
    }

    @Override
    public ShopDataResult findShopsIncomeByTimeScope(ProDataViewParam param) {
        List<Map<String, Object>> businessData = businessMapper.findBusinessDataOrderByIncome(param);

        BigDecimal incomeTotal=BigDecimal.ZERO;
        if(CollectionUtil.isNotEmpty(businessData)){
            for(Map<String, Object> data:businessData){
                incomeTotal=incomeTotal.add(data.get("income") == null ? BigDecimal.ZERO : (BigDecimal) data.get("income"));
            }
        }
        ShopDataResult dataInfoResult=new ShopDataResult();
        dataInfoResult.setList(businessData);
        dataInfoResult.setIncomeTotal(incomeTotal);

        return dataInfoResult;
    }



    @Override
    public List<Map<String, Object>> findBusinessDataOrderByPeopleQty(ProDataViewParam param) {
        List<Map<String, Object>> businessData = businessMapper.findBusinessDataOrderByPeopleQty(param);
        return businessData;
    }

    @Override
    public List<Map<String, Object>> findBusinessDataOfFirstDay(ProDataViewParam param,  List<Map<String, Object>> shopInfoMapList) {

        Map<String,Map<String, Object>> shopMap=new HashMap<>();
        List<Map<String, Object>> resultList=new ArrayList<>();
        if(CollectionUtil.isNotEmpty(shopInfoMapList)){
            for(Map<String, Object> shop:shopInfoMapList){
                shopMap.put(shop.get("shopId").toString().trim(),shop);
            }
        }


        List<Map<String, Object>> businessData = new ArrayList<>();
        Map<String, BigDecimal> incomeMap = new HashMap<>();

        //TODO-1 所有的新店


        //TODO-2 所有的新店的首日营业收入
        if (CollectionUtil.isNotEmpty(shopInfoMapList)) {
            for (Map<String, Object> dataResult : shopInfoMapList) {
                ProDataViewParam par = new ProDataViewParam();
                List<Integer> paramList = new ArrayList<>();
                paramList.add(Integer.parseInt(dataResult.get("shopId").toString()));
                par.setParamList(paramList);
                par.setStartTime(dataResult.get("openDay").toString().trim() + " 04:00:00");
                par.setEndTime(DateUtil.get4OclockByDay(dataResult.get("openDay").toString().trim()));
                //此处只查单店用这个sql就行
                par.setLimit(2);
                List<Map<String, Object>> dataMap = businessMapper.findBusinessDataOrderByIncome(par);

                if (CollectionUtil.isNotEmpty(dataMap) && dataMap.get(0) != null && dataMap.get(0).get("income") != null) {
                    dataMap.get(0).put("openDay", dataResult.get("openDay").toString().trim());
                    businessData.add(dataMap.get(0));
                    //营业额
                    if (param.getType() == 1) {
                        incomeMap.put(dataMap.get(0).get("shopId").toString(), (BigDecimal) dataMap.get(0).get("income"));
                    }
                    //客流量
                    if (param.getType() == 2) {
                        incomeMap.put(dataMap.get(0).get("shopId").toString(), (BigDecimal) dataMap.get(0).get("peopleQty"));
                    }

                }
            }
        }


        //TODO-3 返回结果
        LinkedHashMap<String, BigDecimal> linkedHashMap = sortMap(incomeMap, param.getLimit());
        if(CollectionUtil.isNotEmpty(incomeMap)){
            for(Map.Entry<String, BigDecimal> entry : linkedHashMap.entrySet()){
                String key = entry.getKey();
                BigDecimal val = entry.getValue();

                Map<String, Object> map = shopMap.get(key);
                map.put("value",val);
                resultList.add(map);
            }
        }


        return resultList;
    }

    @Override
    public  List<Map<String, Object>> findPeopleQtyByParam(ProDataViewParam param) {
        List<Map<String, Object>> businessData = businessMapper.findPeopleQtyByParam(param);
        return businessData;
    }

    @Override
    public List<Map<String, Object>> findTakeawayRiceDataByParam(ProDataViewParam param) {
        List<Map<String, Object>> businessData = businessMapper.findTakeawayRiceDataByParam(param);
        return businessData;
    }


    private Page getPageContext() {
        return LayuiPageFactory.defaultPage();
    }

    public static LinkedHashMap<String, BigDecimal> sortMap(Map<String, BigDecimal> map, Integer limit) {
        class MapClass {                                                            //自定义类保存键值对
            private String key;
            private BigDecimal value;

            public MapClass(String key, BigDecimal value) {
                super();
                this.key = key;
                this.value = value;
            }

            public String getKey() {
                return key;
            }

            public BigDecimal getValue() {
                return value;
            }


        }
        class MapSortMethod implements Comparator<MapClass> {                    //为自定义类实现排序方法
            @Override
            public int compare(MapClass o1, MapClass o2) {
                //int result = Integer.compare(o1.getValue(), o2.getValue());        //按值大小升序排列
                int result = compareBig(o2.getValue(), o1.getValue());    //按值大小降序排列
                if (result != 0) {
                    return result;
                }
                return o1.getKey().compareTo(o2.getKey());                        //值相同时按键字典顺序排列
            }
        }

        List<MapClass> mapclass = new ArrayList<MapClass>();                //以ArrayList保存自定义类
        for (String k : map.keySet()) {
            mapclass.add(new MapClass(k, map.get(k)));
        }
        Collections.sort(mapclass, new MapSortMethod());                        //使用Collections.sort()方法，第二个参数为自定义排序方法，需要实现Comparator接口

        if (limit != null && mapclass.size() > limit) {
            mapclass = mapclass.subList(0, limit);
        }

        LinkedHashMap<String, BigDecimal> sortedMap = new LinkedHashMap<String, BigDecimal>();
        for (MapClass m : mapclass) {
            sortedMap.put(m.getKey(), m.getValue());
        }
        return sortedMap;                                                        //用LinkedHashMap返回排好序的Map
    }

    public static int compareBig(BigDecimal x, BigDecimal y) {
        return (x.compareTo(y) == -1) ? -1 : ((x.compareTo(y) == 0) ? 0 : 1);
    }

}
